package cn.springBoot;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author xuqingchen
 */
@Component
public final class Encrypt {

    private final static Charset utf8 = Charset.forName("utf-8");
    private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();

    /**
     * 使用AES加密
     *
     * @param key
     *            加密密钥
     * @param in
     *            明文数据
     * @return 密文数据(base64)
     */
    public static String ecryptByAes(String key, String in) throws Exception {
        return ecryptByAes(key, in, null);
    }

    /**
     * 使用AES加密
     *
     * @param key
     *            加密密钥
     * @param in
     *            明文数据
     * @param iv
     *            加密参数
     * @return 密文数据(base64)
     */
    public static String ecryptByAes(String key, String in, String iv) throws Exception {
        // if (Strings.isNullOrEmpty(in)) {
        // throw new IllegalArgumentException("缺少明文数据");
        // }

        byte[] out = aesCipher(key, Cipher.ENCRYPT_MODE, iv).doFinal(in.getBytes(utf8));
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * 使用AES解密
     *
     * @param key
     *            解密密钥
     * @param in
     *            密文数据
     * @return 明文数据(utf8编码)
     */
    public static String decryptByAes(String key, String in) throws Exception {
        return decryptByAes(key, in, null);
    }

    /**
     * 使用AES解密
     *
     * @param key
     *            解密密钥
     * @param in
     *            密文数据
     * @return 明文数据(utf8编码)
     */
    public static String decryptByAes(String key, String in, String iv) throws Exception {
        // if (Strings.isNullOrEmpty(in)) {
        // throw new IllegalArgumentException("缺少密文数据");
        // }

        byte[] data = Base64.getDecoder().decode(in);
        byte[] out = aesCipher(key, Cipher.DECRYPT_MODE, iv).doFinal(data);
        return new String(out, utf8);
    }

    /**
     * 对字符串进行MD5编码后转为16进制字符串
     *
     * @param in
     *            源字符串
     * @param salt
     *            混淆字符串
     */
    public static String md5(String in, String salt) {
        byte[] out = digest("MD5", in, salt, utf8);
        if (out == null) {
            return null;
        }
        return toHexString(out);
    }

    /**
     * 转换字节数组为16进制字串
     *
     * @param a
     *            字节数组
     * @return 16进制字串
     */
    public static String toHexString(byte[] a) {
        StringBuilder buf = new StringBuilder(a.length * 2);
        for (byte n : a) {
            int v = n < 0 ? n + 256 : n;
            buf.append(HEX_DIGITS[v >> 4]).append(HEX_DIGITS[v % 16]);
        }
        return buf.toString();
    }

    private static Cipher aesCipher(String key, int mode, String iv) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(utf8), "AES");

        if (iv == null) {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(mode, keySpec);
            return cipher;
        }

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(mode, keySpec, new IvParameterSpec(iv.getBytes(utf8)));
        return cipher;
    }

    private static byte[] digest(String algorithm, String src, String salt, Charset charset) {
        try {
            byte[] a = (charset == null) ? src.getBytes(utf8) : src.getBytes(charset);
            if (salt != null && salt.length() > 0) {
                byte[] b = (charset == null) ? salt.getBytes(utf8) : salt.getBytes(charset);
                a = merge(a, b);
            }
            return MessageDigest.getInstance(algorithm).digest(a);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 合并两个字节数组
     *
     * @param x
     *            第一个字节数组
     * @param y
     *            第二个字节数组
     */
    private static byte[] merge(byte[] x, byte[] y) {
        byte[] b = new byte[x.length + y.length];

        System.arraycopy(x, 0, b, 0, x.length);
        System.arraycopy(y, 0, b, x.length, y.length);

        return b;
    }

    public static void main(String[] args) {
        try {
            String phone = "";
            String[] ps = phone.split("\n");
            for (String str : ps) {
                System.out.println("PhoneTest.Test:" + Encrypt.ecryptByAes("FGbz5QbT95usuCtHC4q6aKna9sp0OnRF", str));
            }

            String en = "sEP/bqgtJV7Au4DTqYmO8Rx8WHnaDn30s398lKfGyT4=\n" + "ykJAYz97DCrzjk1KPFuPfw==\n"
                + "AXSNtBdeGaIC+W329WU95A==";
            String[] ens = en.split("\n");
            int count = 0;
            for (String str : ens) {

                if (!StringUtils.isEmpty(str)) {
                    count++;
                    System.out.println(Encrypt.decryptByAes("FGbz5QbT95usuCtHC4q6aKna9sp0OnRF", str));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}